/**
 * 
 */
package edu.uniquindio.transformador.mundo;

import java.util.Stack;

/**
 * @author 
 *	CENApKNrAsNpsKNpa
 */
public class ArbolBinario 
{
	private Nodo raiz;
	private Transformador transformador;

	public ArbolBinario(Transformador transformador)
	{
		this.transformador = transformador;
	}

	public void crearArbolInfijo(String proposicion) throws Exception
	{
		boolean validacion = transformador.validarParentesis(proposicion);

		if(validacion)
		{
			proposicion = transformador.aPostfija(proposicion);
			raiz = iniciarArbol(proposicion);
		}
		else
			throw new Exception();
	}

	public String crearArbolPolaco(String proposicion) throws Exception
	{
		char valor = proposicion.charAt(0);
		proposicion = quitarCaracterInicial(proposicion);
		System.out.println(proposicion);
		raiz = new Nodo(null, null, valor);
		return iniciarArbol(raiz, proposicion);
	}

	private boolean isHoja(Nodo nodo)
	{
		if(nodo.getIzq() == null && nodo.getDer() == null)
			return true;
		else
			return false;
	}

	public double evaluarForma(Nodo raiz, int x)
	{
		if (isHoja(raiz) == true)
		{
			/*
			 * Si el nodo es una hoja solo debe tener un caracter
			 * si este es una letra se supone que debe ser una variable
			 * y se reemplaza por el numero x en el que se evalua la funcion
			 */
			if(Character.isLetter(raiz.getValor()))
			{
				return 0;
			}
			else //Se supone que si no es una variable es un numero
				return 1;
		}
		else
		{
			if (raiz.getValor() == Constantes.NEGADOR_INFIJO)
			{
				return evaluarForma(raiz.getDer(), x);
			}
			else
			{
				if(transformador.esUnOperador(raiz.getValor()))
				{
					return evaluarForma(raiz.getDer(), x) + evaluarForma(raiz.getIzq(), x);
				}
				else
					return 1;
			}

		}
	}



	private String iniciarArbol(Nodo raiz, String prop) throws Exception
	{
		if(prop == null || prop.length() == 0 || !transformador.esUnOperador(raiz.getValor()))
			return prop;

		char elem = prop.charAt(0);
		prop = quitarCaracterInicial(prop);

		if(raiz.getValor() == Constantes.NEGADOR_INFIJO || raiz.getValor() == Constantes.NEGADOR_POLACO)
		{
			raiz.setDer(new Nodo(null, null, elem));
			prop = iniciarArbol(raiz.getDer(), prop);
		}
		else
		{
			raiz.setIzq(new Nodo(null, null, elem));
			prop = iniciarArbol(raiz.getIzq(), prop);
		}

		if(transformador.esOperadorBinario(raiz.getValor()) && !tieneDerecha(raiz))
		{
			char elem2 = prop.charAt(0);
			prop = quitarCaracterInicial(prop);
			raiz.setDer(new Nodo(null, null, elem2));
			prop = iniciarArbol(raiz.getDer(), prop);
		}
		else
			return prop;

		return prop;
	}

	private Nodo iniciarArbol(String funcion) throws Exception
	{
		Stack<Nodo> pila = new Stack<Nodo>();

		for (int i = 0; i < funcion.length(); i++)
		{
			Nodo nodo = new Nodo();
			nodo.setValor(funcion.charAt(i));

			if(Character.isLetter(funcion.charAt(i)))
			{
				pila.push(nodo);
			}
			else
			{
				if(transformador.esUnOperador(funcion.charAt(i)))
				{
					if(funcion.charAt(i) == Constantes.NEGADOR_INFIJO || funcion.charAt(i) == Constantes.NEGADOR_POLACO)
					{
						nodo.setDer(pila.pop());
						nodo.setIzq(null);
						pila.push(nodo);
					}
					else
					{
						nodo.setDer(pila.pop());
						nodo.setIzq(pila.pop());
						pila.push(nodo);
					}
				}
			}
		}
		return pila.pop();
	}



	public String imprimirArbolInfijo(String impresion, Nodo raiz)
	{
		if(raiz != null && raiz.getIzq() != null)
			impresion = imprimirArbolInfijo(impresion, raiz.getIzq());

		impresion += raiz.getValor();

		if(raiz != null && raiz.getDer() != null)
			impresion = imprimirArbolInfijo(impresion, raiz.getDer());

		return impresion;
	}
	
	public String imprimirArbolPreFijo(String impresion, Nodo raiz)
	{
		impresion += raiz.getValor();
		
		if(raiz != null && raiz.getIzq() != null)
			impresion = imprimirArbolPreFijo(impresion, raiz.getIzq());

		if(raiz != null && raiz.getDer() != null)
			impresion = imprimirArbolPreFijo(impresion, raiz.getDer());

		return impresion;
	}

	private String quitarCaracterInicial(String prop)
	{
		return prop.substring(1);
	}

	private boolean tieneDerecha(Nodo nodo)
	{
		if(nodo.getDer()!=null)
			return true;
		return false;
	}

	/**
	 * @return the raiz
	 */
	public Nodo getRaiz() {
		return raiz;
	}

	/**
	 * @param raiz the raiz to set
	 */
	public void setRaiz(Nodo raiz) {
		this.raiz = raiz;
	}

}
